var SCREEN_WIDTH = 256;
var SCREEN_HEIGHT = 240;
var FRAMEBUFFER_SIZE = SCREEN_WIDTH * SCREEN_HEIGHT;

var canvas_ctx, image;
var framebuffer_u8, framebuffer_u32;

var AUDIO_BUFFERING = 512;
var SAMPLE_COUNT = 4 * 1024;
var SAMPLE_MASK = SAMPLE_COUNT - 1;
var audio_samples_L = new Float32Array(SAMPLE_COUNT);
var audio_samples_R = new Float32Array(SAMPLE_COUNT);
var audio_write_cursor = 0,
	audio_read_cursor = 0;

var audio_ctx = undefined








var nes = new jsnes.NES({
	onFrame: function(framebuffer_24) {
		for (var i = 0; i < FRAMEBUFFER_SIZE; i++) framebuffer_u32[i] = 0xFF000000 | framebuffer_24[i];
	},
	onAudioSample: function(l, r) {
		// console.log(l,r)
		audio_samples_L[audio_write_cursor] = l;
		audio_samples_R[audio_write_cursor] = r;
		audio_write_cursor = (audio_write_cursor + 1) & SAMPLE_MASK;
	},
});




function onAnimationFrame() {
	nes.frame();
	image.data.set(framebuffer_u8);
	canvas_ctx.putImageData(image, 0, 0);
	window.requestAnimationFrame(onAnimationFrame);


}

function audio_remain() {
	return (audio_write_cursor - audio_read_cursor) & SAMPLE_MASK;
}

function audio_callback(event) {
	var dst = event.outputBuffer;
	var len = dst.length;

	// Attempt to avoid buffer underruns.
	if (audio_remain() < AUDIO_BUFFERING) nes.frame();

	var dst_l = dst.getChannelData(0);
	var dst_r = dst.getChannelData(1);
	for (var i = 0; i < len; i++) {
		var src_idx = (audio_read_cursor + i) & SAMPLE_MASK;
		dst_l[i] = audio_samples_L[src_idx];
		dst_r[i] = audio_samples_R[src_idx];
	}

	audio_read_cursor = (audio_read_cursor + len) & SAMPLE_MASK;
}

function keyboard(callback, event) {
	var player = 1;
	// console.log(event)
	//连发 连跳逻辑
	if (event.type == 'keydown') {
		// console.log('--设置')

		switch (event.keyCode) {
			case 73:
				if (lineAKey == undefined) {

					lineAKey = setInterval(function() {
						lineKeyA(75)
					}, 20)

				}
				break;
			case 85:
				if (lineBKey == undefined) {

					lineBKey = setInterval(function() {
						lineKeyB(74)
					}, 20)

				}
				break;
		}

	} else if (event.type == 'keyup') {
		switch (event.keyCode) {
			case 73:
				clearInterval(lineAKey)
				lineAKey = undefined
				break;
			case 85:
				clearInterval(lineBKey)
				lineBKey = undefined
				break;
		}
	}

	switch (event.keyCode) {
		case 87: // UP
			callback(player, jsnes.Controller.BUTTON_UP);
			break;
		case 83: // Down
			callback(player, jsnes.Controller.BUTTON_DOWN);
			break;
		case 65: // Left
			callback(player, jsnes.Controller.BUTTON_LEFT);
			break;
		case 68: // Right
			callback(player, jsnes.Controller.BUTTON_RIGHT);
			break;
		case 75:
			callback(player, jsnes.Controller.BUTTON_A);
			break
		case 73:
			break;
		case 74:
			callback(player, jsnes.Controller.BUTTON_B);
			break;
		case 85:
			break;

		case 70: // Tab
			callback(player, jsnes.Controller.BUTTON_SELECT);
			break;
		case 71: // Return
			callback(player, jsnes.Controller.BUTTON_START);
			break;
		default:
			break;
	}
}

let lineBKey = undefined
let lineAKey = undefined

function lineKeyB(code) {
	// console.log('---模拟--'+code)
	simulateKeyPress(code)
	setTimeout(function() {
		simulateKeyRelease(code)
	}, 10)
}

function lineKeyA(code) {
	// console.log('---模拟--'+code)
	simulateKeyPress(code)
	setTimeout(function() {
		simulateKeyRelease(code)
	}, 10)
}


//模拟按下
function simulateKeyPress(keyCode) {
	const event = new KeyboardEvent('keydown', {
		keyCode: keyCode
	});
	document.dispatchEvent(event);
}

// 模拟按键弹起
function simulateKeyRelease(keyCode) {
	const event = new KeyboardEvent('keyup', {
		keyCode: keyCode
	});
	document.dispatchEvent(event);
}


function nes_init(canvas_id) {
	var canvas = document.getElementById(canvas_id);
	canvas_ctx = canvas.getContext("2d");
	image = canvas_ctx.getImageData(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

	canvas_ctx.fillStyle = "black";
	canvas_ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

	// Allocate framebuffer array.
	var buffer = new ArrayBuffer(image.data.length);
	framebuffer_u8 = new Uint8ClampedArray(buffer);
	framebuffer_u32 = new Uint32Array(buffer);

	// Setup audio.
	audio_ctx = new window.AudioContext();
	var script_processor = audio_ctx.createScriptProcessor(AUDIO_BUFFERING, 0, 2);
	script_processor.onaudioprocess = audio_callback;
	script_processor.connect(audio_ctx.destination);
}

function nes_boot(rom_data) {
	nes.loadROM(rom_data);
	// nes.frame();
	window.requestAnimationFrame(onAnimationFrame);
}

function nes_load_data(canvas_id, rom_data) {
	nes_init(canvas_id);
	nes_boot(rom_data);
}

function nes_load_url(canvas_id, path) {
	nes_init(canvas_id);

	var req = new XMLHttpRequest();
	req.open("GET", path);
	req.overrideMimeType("text/plain; charset=x-user-defined");
	req.onerror = () => console.log(`Error loading ${path}: ${req.statusText}`);
	app.loading = true
	req.onload = function() {
		if (this.status === 200) {
			try {
				nes_boot(this.responseText);
			} catch (error) {
				console.log(error)
				app.$message.error('该游戏暂不支持！');
			}

			app.loading = false
			setTimeout(function() {
				let data = localStorage.getItem(path)
				if (data != null && data != undefined) {
					getData(app.gameInfo.nesUrl)
					app.$message.success('存档读取成功！');
					return;
				}

				localforage.getItem(app.gameInfo.nesUrl).then(function(value) {
					if (value != null && value != undefined) {
						if (JSON.stringify(value).startsWith("{")) {
							nes.fromJSON(value)
							app.$message.success('存档读取成功！');
						} else {
							nes.fromJSON(JSON.parse(LZString.decompressFromBase64(value)))
							app.$message.success('存档读取成功！');
						}
					}

				}).catch(function(error) {
					// app.$message.error('存档读取失败！');
				});


			}, 100)
		} else if (this.status === 0) {
			// Aborted, so ignore error
		} else {
			req.onerror();
		}
	};

	req.send();
}


function saveData(key) {
	audio_ctx.suspend();
	localforage.setItem(key, LZString.compressToBase64(JSON.stringify(nes.toJSON()))).then(function() {
		app.$message.success('存档保存成功！');
		audio_ctx.resume();
	}).catch(function(error) {
		app.$message.error('存档保存失败！');
		audio_ctx.resume();
	});



}

function getData(key) {
	// console.log(nes)
	let data = JSON.parse(localStorage.getItem(key));
	// nes.reset()
	nes.fromJSON(data)
	// nes.reloadROM()

}



document.addEventListener('keydown', (event) => {
	keyboard(nes.buttonDown, event)
});
document.addEventListener('keyup', (event) => {
	keyboard(nes.buttonUp, event)
});
